#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif

#include "sweety.h"
#ifndef SW_DISABLE

#ifndef SW_DEFINE_MATH_OPERATORS
#define SW_DEFINE_MATH_OPERATORS
#endif
#include "sweety_Internal.h"

// System includes
#include <ctype.h>      // toupper
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
#include <stddef.h>     // intptr_t
#else
#include <stdint.h>     // intptr_t
#endif

//-------------------------------------------------------------------------
// Warnings
//-------------------------------------------------------------------------

// Visual Studio warnings
#ifdef _MSC_VER
#pragma warning (disable: 4127)     // condition expression is constant
#pragma warning (disable: 4996)     // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later
#pragma warning (disable: 5054)     // operator '|': deprecated between enumerations of different types
#endif
#endif

// Clang/GCC warnings with -Weverything
#if defined(__clang__)
#if __has_warning("-Wunknown-warning-option")
#pragma clang diagnostic ignored "-Wunknown-warning-option"         // warning: unknown warning group 'xxx'                      // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
#endif
#pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
#pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                            // yes, they are more terse.
#pragma clang diagnostic ignored "-Wfloat-equal"                    // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
#pragma clang diagnostic ignored "-Wformat-nonliteral"              // warning: format string is not a string literal            // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
#pragma clang diagnostic ignored "-Wsign-conversion"                // warning: implicit conversion changes signedness
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0
#pragma clang diagnostic ignored "-Wdouble-promotion"               // warning: implicit conversion from 'float' to 'double' when passing argument to function  // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
#pragma clang diagnostic ignored "-Wenum-enum-conversion"           // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_')
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wpragmas"                          // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wformat-nonliteral"                // warning: format not a string literal, format string not checked
#pragma GCC diagnostic ignored "-Wclass-memaccess"                  // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif

static SwVec2 GetCurWindowAbsoluteCoords2D()
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;
    SW_ASSERT(window);

    return (window->Pos + SwVec2(5, 20));
}

/* Primitives */

void SW::Line(const SwVec2& p1, const SwVec2& p2, SwU32 col, float thickness)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddLine(cur_absolute_coord + p1, cur_absolute_coord + p2, col, thickness);
}

void SW::Rect(const SwVec2& p_min, const SwVec2& p_max, SwU32 col, float rounding, SwDrawFlags flags, float thickness)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddRect(cur_absolute_coord + p_min, cur_absolute_coord + p_max, col, rounding, flags, thickness);
}

void SW::RectFilled(const SwVec2& p_min, const SwVec2& p_max, SwU32 col, float rounding, SwDrawFlags flags)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddRectFilled(cur_absolute_coord + p_min, cur_absolute_coord + p_max, col, rounding, flags);
}

void SW::RectFilledMultiColor(const SwVec2& p_min, const SwVec2& p_max, SwU32 col_upr_left, SwU32 col_upr_right, SwU32 col_bot_right, SwU32 col_bot_left)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddRectFilledMultiColor(cur_absolute_coord + p_min, cur_absolute_coord + p_max, col_upr_left, col_bot_right, col_bot_right, col_bot_left);
}

void SW::Quad(const SwVec2& p1, const SwVec2& p2, const SwVec2& p3, const SwVec2& p4, SwU32 col, float thickness)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddQuad(cur_absolute_coord + p1, cur_absolute_coord + p2, cur_absolute_coord + p3, cur_absolute_coord + p4, col, thickness);
}

void SW::QuadFilled(const SwVec2& p1, const SwVec2& p2, const SwVec2& p3, const SwVec2& p4, SwU32 col)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddQuadFilled(cur_absolute_coord + p1, cur_absolute_coord + p2, cur_absolute_coord + p3, cur_absolute_coord + p4, col);
}

void SW::Triangle(const SwVec2& p1, const SwVec2& p2, const SwVec2& p3, SwU32 col, float thickness)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddTriangle(cur_absolute_coord + p1, cur_absolute_coord + p2, cur_absolute_coord + p3, col, thickness);
}

void SW::TriangleFilled(const SwVec2& p1, const SwVec2& p2, const SwVec2& p3, SwU32 col)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddTriangleFilled(cur_absolute_coord + p1, cur_absolute_coord + p2, cur_absolute_coord + p3, col);
}

void SW::Circle(const SwVec2& center, float radius, SwU32 col, int num_segments, float thickness)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddCircle(cur_absolute_coord + center, radius, col, num_segments, thickness);
}

void SW::CircleFilled(const SwVec2& center, float radius, SwU32 col, int num_segments)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddCircleFilled(cur_absolute_coord + center, radius, col, num_segments);
}

void SW::Ngon(const SwVec2& center, float radius, SwU32 col, int num_segments, float thickness)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddNgon(cur_absolute_coord + center, radius, col, num_segments, thickness);
}

void SW::NgonFilled(const SwVec2& center, float radius, SwU32 col, int num_segments)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddNgonFilled(cur_absolute_coord + center, radius, col, num_segments);
}

void SW::Polyline(SwVec2* points, int num_points, SwU32 col, SwDrawFlags flags, float thickness)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    for (int i = 0; i < num_points; i++)
    {
        points[i] += cur_absolute_coord;
    }
    window->DrawList->AddPolyline(points, num_points, col, flags, thickness);
}

void SW::ConvexPolyFilled(SwVec2* points, int num_points, SwU32 col)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    for (int i = 0; i < num_points; i++)
    {
        points[i] += cur_absolute_coord;
    }
    window->DrawList->AddConvexPolyFilled(points, num_points, col);
}

void SW::BezierCubic(const SwVec2& p1, const SwVec2& p2, const SwVec2& p3, const SwVec2& p4, SwU32 col, float thickness, int num_segments)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddBezierCubic(cur_absolute_coord + p1, cur_absolute_coord + p2, cur_absolute_coord + p3, cur_absolute_coord + p4, col, thickness, num_segments);
}

void SW::BezierQuadratic(const SwVec2& p1, const SwVec2& p2, const SwVec2& p3, SwU32 col, float thickness, int num_segments)
{
    SwGuiContext& g = *GMUI_Ctx;
    SwGuiWindow* window = g.CurrentWindow;

    const SwVec2 cur_absolute_coord = GetCurWindowAbsoluteCoords2D();
    window->DrawList->AddBezierQuadratic(cur_absolute_coord + p1, cur_absolute_coord + p2, cur_absolute_coord + p3, col, thickness, num_segments);
}

#endif // #ifndef SW_DISABLE